package token

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"errors"
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"net/http"
	"strings"
	"time"
)

type EcdsaUser struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}
type EcdsaClaims struct {
	UserId string `json:"user_id"`
	jwt.StandardClaims
}

var (
	err3          error
	eccPrivateKey *ecdsa.PrivateKey
	eccPublicKey  *ecdsa.PublicKey
)

func init() {
	eccPrivateKey, eccPublicKey, err3 = getEcdsaKey(2)
	if err3 != nil {
		panic(err3)
		return
	}
}

// ecdsa秘钥生成
func getEcdsaKey(keyType int) (*ecdsa.PrivateKey, *ecdsa.PublicKey, error) {
	var err error
	var pri_key *ecdsa.PrivateKey
	var pub_key *ecdsa.PublicKey
	var curve elliptic.Curve //椭圆曲线
	switch keyType {
	case 1:
		curve = elliptic.P224()
	case 2:
		curve = elliptic.P256()
	case 3:
		curve = elliptic.P384()
	case 4:
		curve = elliptic.P521()
	default:
		err = errors.New("输入的签名key类型错误！key取值：\n 1:椭圆曲线224\n 2:椭圆曲线2256\n 3:椭圆曲线384\n 4:椭圆曲线521\n")
		return nil, nil, err
	}
	pri_key, err = ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil, nil, err
	}
	pub_key = &pri_key.PublicKey
	return pri_key, pub_key, err
}

func EcdsaCreateToken(c *gin.Context) {
	u := EcdsaUser{}
	err := c.Bind(&u)
	if err != nil {
		c.JSON(http.StatusBadRequest, "参数错误")
		return
	}
	token, err := _ecdsaCreateToken(u)
	if err != nil {
		c.JSON(http.StatusBadRequest, "生成token错误")
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"code": http.StatusOK,
		"msg":  "授权成功",
		"data": token,
	})
}

// 生成token
func _ecdsaCreateToken(u EcdsaUser) (interface{}, error) {
	claims := &EcdsaClaims{
		UserId: u.ID,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(7 * 24 * time.Hour).Unix(),
			Issuer:    "renxing",
		},
	}
	token := jwt.NewWithClaims(jwt.SigningMethodES256, claims)
	signedString, err := token.SignedString(eccPrivateKey)
	return signedString, err
}

// token认证中间件
func EcdsaAuthMiddleware(c *gin.Context) {
	auth := "renxing"
	tokenString := c.GetHeader("Authorization")
	if tokenString == "" || !strings.HasPrefix(tokenString, auth+":") {
		c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "无效的token"})
		c.Abort()
		return
	}
	index := strings.Index(tokenString, auth+":")
	tokenString = tokenString[index+len(auth)+1:]
	claims, err := _ecdsaJwtTokenRead(tokenString)
	if err != nil {
		c.AbortWithStatusJSON(http.StatusUnauthorized, err)
		return
	}
	claimsValue := claims.(jwt.MapClaims)
	if claimsValue["user_id"] == nil {
		c.AbortWithStatusJSON(http.StatusUnauthorized, "id不存在")
		return
	}
	u := EcdsaUser{}
	c.Bind(&u)
	if u.ID != claimsValue["user_id"] {
		c.JSON(http.StatusUnauthorized, gin.H{"code": http.StatusUnauthorized, "msg": "用户不存在"})
		c.Abort()
		return
	}
	c.Next()
}

// token解析
func _ecdsaJwtTokenRead(tokenString string) (interface{}, error) {
	myToken, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
		if _, ok := token.Method.(*jwt.SigningMethodECDSA); !ok {
			return nil, fmt.Errorf("无效的签名方法: %v", token.Method)
		}
		return eccPublicKey, nil
	})
	if claims, ok := myToken.Claims.(jwt.MapClaims); ok && myToken.Valid {
		return claims, nil
	}
	return nil, err
}
